package cn.zl.web.impl.user;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.StrUtil;
import cn.yunbamboos.exception.AppException;
import cn.yunbamboos.mybatis.conditions.Conditions;
import cn.yunbamboos.id.SnowflakeIdGenerator;
import cn.yunbamboos.rest.service.anno.RestServiceMapping;
import cn.yunbamboos.rest.service.dto.Page;
import cn.yunbamboos.rest.service.dto.out.BaseOutDTO;
import cn.yunbamboos.rest.service.transaction.Transaction;
import cn.yunbamboos.utils.UserPasswordUtils;
import cn.zl.web.dto.user.AddUserInDTO;
import cn.zl.web.dto.user.AddUserOutDTO;
import cn.zl.web.dto.user.ChangeUserPasswordInDTO;
import cn.zl.web.dto.user.ChangeUserPasswordOutDTO;
import cn.zl.web.dto.user.DeleteUserInDTO;
import cn.zl.web.dto.user.DeleteUserOutDTO;
import cn.zl.web.dto.user.QueryCurLoginUserInDTO;
import cn.zl.web.dto.user.QueryCurLoginUserOutDTO;
import cn.zl.web.dto.user.QueryUserByPageInDTO;
import cn.zl.web.dto.user.QueryUserByPageOutDTO;
import cn.zl.web.dto.user.ResetUserPasswordInDTO;
import cn.zl.web.dto.user.ResetUserPasswordOutDTO;
import cn.zl.web.dto.user.UpdateUserInDTO;
import cn.zl.web.dto.user.UpdateUserOutDTO;
import cn.zl.web.inter.user.IUserService;
import cn.zl.mapper.UserMapper;
import cn.zl.model.User;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

@Service("UserServiceImpl")
public class UserServiceImpl implements IUserService {

    @Resource
    private UserMapper userMapper;
    @Resource
    private SnowflakeIdGenerator snowflakeIdGenerator;

    @RestServiceMapping(url = "/web/user/queryCurLoginUser", name = "查询当前登陆用户信息服务", in = QueryCurLoginUserInDTO.class, out = QueryCurLoginUserOutDTO.class)
    @Override
    public BaseOutDTO queryCurLoginUser(QueryCurLoginUserInDTO in) {
        Long userId = in.getSessionRequiredLong("user_id");
        Optional<User> optional = userMapper.queryByPrimaryKey(userId);
        if (optional.isEmpty()) {
            throw AppException.c("用户不存在");
        }
        return new QueryCurLoginUserOutDTO(optional.get());
    }

    @RestServiceMapping(url = "/web/user/queryByPage", name = "条件分页查询用户列表服务", in = QueryUserByPageInDTO.class, out = QueryUserByPageOutDTO.class)
    @Override
    public BaseOutDTO queryByPage(QueryUserByPageInDTO in) {
        // 创建分页对象
        Page<User> page = new Page<>(in.getPageNo(), in.getPageSize());
        // 添加动态条件
        Conditions where = new Conditions();
        // 查询总数
        int total = userMapper.countForPage(page, where);
        // 查询当前页码数据
        List<User> list = userMapper.queryForPage(page, where);
        page.setRows(list).setTotal(total);
        return new QueryUserByPageOutDTO(page);
    }

    @RestServiceMapping(url = "/web/user/add", name = "添加新用户服务", in = AddUserInDTO.class, out = AddUserOutDTO.class, transaction = Transaction.WRITE)
    @Override
    public BaseOutDTO add(AddUserInDTO in) {
        User user = in.getUser();
        if (userMapper.existLoginName(user.getLoginName())) {
            throw AppException.c("login_name({0}) is exist", user.getLoginName());
        }
        // 生成用户ID
        user.setUserId(snowflakeIdGenerator.nextId());
        // 加密密码
        user.setPassword(UserPasswordUtils.encrypt(user.getPassword()));
        user.setCreateTime(LocalDateTimeUtil.format(LocalDateTime.now(), DatePattern.NORM_DATETIME_PATTERN));
        userMapper.insert(user);
        return new AddUserOutDTO();
    }

    @RestServiceMapping(url = "/web/user/update", name = "修改用户服务", in = UpdateUserInDTO.class, out = UpdateUserOutDTO.class, transaction = Transaction.WRITE)
    @Override
    public BaseOutDTO update(UpdateUserInDTO in) {
        User user = in.getUser();
        userMapper.update(user);
        return new UpdateUserOutDTO();
    }

    @RestServiceMapping(url = "/web/user/delete", name = "删除用户服务", in = DeleteUserInDTO.class, out = DeleteUserOutDTO.class, transaction = Transaction.WRITE)
    @Override
    public BaseOutDTO delete(DeleteUserInDTO in) {
        String curUserId = in.getSession("user_id");
        if (StrUtil.isBlank(curUserId)) {
            throw AppException.c("用户登陆失效,请重新登陆");
        }
        in.forEach(userId -> {
            if ("1".equals(userId)) {
                throw AppException.c("默认用户不能删除");
            }
            if (curUserId.equals(userId)) {
                throw AppException.c("当前登陆账户不能删除");
            }
            userMapper.deleteByPrimaryKey(userId);
        });
        return new DeleteUserOutDTO();
    }

    @RestServiceMapping(url = "/web/user/change-password", name = "修改用户密码服务", in = ChangeUserPasswordInDTO.class, out = ChangeUserPasswordOutDTO.class, transaction = Transaction.WRITE)
    @Override
    public BaseOutDTO changePassword(ChangeUserPasswordInDTO in) {
        long userId = in.getSessionRequiredLong("user_id");
        Optional<User> optional = userMapper.queryByPrimaryKey(userId);
        if (optional.isEmpty()) {
            throw AppException.c("未查询到用户");
        }
        User user = optional.get();
        String oldPassword = UserPasswordUtils.encrypt(in.getOldPassword());
        if (!oldPassword.equals(user.getPassword())) {
            throw AppException.c("旧密码错误");
        }
        String newPassword = UserPasswordUtils.encrypt(in.getNewPassword());
        userMapper.updatePassword(userId, newPassword);
        return new ChangeUserPasswordOutDTO();
    }

    @RestServiceMapping(url = "/web/user/reset-password", name = "管理员重置用户密码服务", in = ResetUserPasswordInDTO.class, out = ResetUserPasswordOutDTO.class, transaction = Transaction.WRITE)
    @Override
    public BaseOutDTO resetPassword(ResetUserPasswordInDTO in) {
        long curUserId = in.getSessionRequiredLong("user_id");
        if (curUserId == 1) {
            long userId = in.getUserId();
            String password = UserPasswordUtils.encrypt(in.getPassword());
            userMapper.updatePassword(userId, password);
        } else {
            throw AppException.c("当前用户无重置密码权限");
        }
        return new ResetUserPasswordOutDTO();
    }

}
